﻿using LightCAD.Core;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text;
using LightCAD.MathLib;


namespace LightCAD.Runtime
{
    /// <summary>
    /// 对应于DocumentControl+Document的运行时管理类
    /// </summary>
    public class DocumentRuntime : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        public LcDocument Document { get; private set; }
        //public ICommandControl CommandCtrl { get; internal set; }
        public List<IDocumentEditor> DocEditors { get; set; }

        public IDocumentEditor DrawingEditRt { get; private set; }
        public IDocumentEditor Model3DEditRt { get; private set; }

        public PropertiesRuntime PropertiesRt { get; internal set; }

        private bool changeNotSaved;
        public bool ChangeNotSaved
        {
            get { return this.changeNotSaved; }
            set
            {
                var changed = (this.changeNotSaved != value);
                this.changeNotSaved = value;
                if (changed) OnPropertyChanged();
            }
        }
        public bool IsActive { get; set; }
        public DocumentAction Action { get; set; }
        public delegate void PropertyUIChangedEvent(List<LcElement> elements);
        public event PropertyUIChangedEvent PropertyUIChanged;
        public delegate void PropertyChangedEvent(); 
        public event PropertyChangedEvent UIPropertyChanged;
        public void UIPropertyChange()
        {
            this.UIPropertyChanged.Invoke();
        }
        public void PropertyUIChange(List <LcElement> elements)
        {
            this.PropertyUIChanged.Invoke(elements);
        }
        public DocumentRuntime(LcDocument document)
        {
            this.Document = document;
            this.Action = new DocumentAction(this);
        }
        public void Instance_CommandExecute(object sender, CommandExecuteEventArgs e)
        {
            if (!this.IsActive) return;//非活动不接受命令
            var vportCmds = new string[] { "UCS", "WCS", "PLAN", "NOPLAN" };
            if (Array.IndexOf(vportCmds, e.Command.Name.ToUpper()) >= 0)
            {
                this.DrawingEditRt.CommandExecute(e.Command);
            }
            var fileCmds = new string[] { "NEW", "OPEN", "SAVE", "SAVEAS", "CLOSE", "SAVECOM", "OPENCOM" };
            if (Array.IndexOf(fileCmds, e.Command.Name.ToUpper()) >= 0)
            {
                ExecuteCommand(e.Command.Name.ToUpper());
            }
        }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name));
        }

        public void Initilize(IDocumentEditor drawingEdit, IDocumentEditor model3DEdit, IPropertyControl propertyCtrl)
        {
            this.DocEditors = new List<IDocumentEditor>();
            this.DrawingEditRt = drawingEdit;
            this.Model3DEditRt = model3DEdit;
            this.DocEditors.Add(drawingEdit);
            this.DocEditors.Add(model3DEdit);
            this.PropertiesRt = new PropertiesRuntime(this, propertyCtrl);
        }

        public void SetActive(bool isActive)
        {
            this.IsActive = isActive;
            this.DrawingEditRt.SetActive(isActive);
        }

        #region Commands

        public void ExecuteCommand(string cmdName)
        {
            switch (cmdName)
            {
                case "NEW": New(); break;
                case "OPEN": Open(); break;
                case "SAVE": Save(); break;
                case "SAVEAS": SaveAs(); break;
                case "CLOSE": CloseFile(); break;
                case "SAVECOM": SaveCom(); break;
                case "OPENCOM": OpenCom(); break;
            }
        }

        public void Erase()
        {
            DocumentManager.CurrentRecorder.BeginAction("ERASE");
            if (this.Action.SelectedElements.Count > 0)
            {
                foreach (var element in this.Action.SelectedElements)
                {
                    (element.Parent as ElementSpace)?.RemoveElement(element);
                }
            }
            this.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }





        public void Copy()
        {
            if (this.Action.SelectedElements.Count == 0) return;
            var elements = new List<LcElement>();
            var box = new Box2();
            box.MakeEmpty();
            foreach (var element in this.Action.SelectedElements)
            {
                box.Union(element.BoundingBox);
                var copyEle = element.Clone();
                elements.Add(copyEle);
            }

            foreach (var element in elements)
            {
                element.Translate(-box.Min.X, -box.Min.Y);
            }

            var dataObject = AppRuntime.UISystem.NewClipboardDataObject();
            var josn = JsonSerializer.Serialize(elements);
            AppRuntime.UISystem.SetClipboardData(dataObject, "LightCAD_Elements", josn);
            AppRuntime.UISystem.SetToClipboard(dataObject);
        }

        internal void Cut()
        {
            if (this.Action.SelectedElements.Count == 0) return;
            Copy();
            DocumentManager.CurrentRecorder.BeginAction("CUT");
            foreach (var element in this.Action.SelectedElements)
            {
                (element.Parent as ElementSpace).RemoveElement(element);
                //this.DrawingEditRt.ActiveViewportRt.ActiveElementSet.RemoveElement(element);
            }
            this.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }


        internal void Undo()
        {
            //VPort.CancelAll();
            DocumentManager.CurrentRecorder.UndoAction();
        }
        internal void Redo()
        {
            DocumentManager.CurrentRecorder.RedoAction();
        }

        public void New()
        {
            DocumentManager.New();
        }

        public const string DrawingFileName = "drawing.json";
        public async void Open()
        {
            await AppRuntime.ActiveMainUI.OpenDocument();
        }

        public async void Save()
        {
            var doc = DocumentManager.Current;
            if (System.IO.File.Exists(doc.FilePath))
            {
                DocumentUtils.Save(doc);
                this.DrawingEditRt.CommandCenter.WriteInfo("保存成功！");
            }
            else
            {
                SaveAs();
            }
        }
        public async void SaveAs()
        {
            var filePath = await AppRuntime.UISystem.SaveFileDialog();
            if (filePath == null) return;
            string fileSuffix = System.IO.Path.GetExtension(filePath);
            var doc = DocumentManager.Current;
            //if (fileSuffix.ToLower() == ".dwg")
            //{
            //    LightCAD.ImpExpDwg.DwgWriter.Export(filePath,
            //                       doc);
            //}
            //else
                DocumentUtils.Save(doc, filePath);
            this.DrawingEditRt.CommandCenter.WriteInfo("保存成功！");
        }

        public async void SaveCom()
        {
            var doc = DocumentManager.Current;
            //if (System.IO.File.Exists(doc.FilePath))
            //{
            //    DocumentUtils.SaveCom(doc);
            //    this.DrawingEditRt.CommandCenter.WriteInfo("保存成功！");
            //}
            //else
            //{
                var filePath = await AppRuntime.UISystem.SaveFileDialog();
                if (filePath == null) return;
                string fileSuffix = System.IO.Path.GetExtension(filePath);
                //if (fileSuffix.ToLower() == ".dwg")
                //{
                //    LightCAD.ImpExpDwg.DwgWriter.Export(filePath,
                //                       doc);
                //}
                //else
                DocumentUtils.SaveCom(doc, filePath);
                this.DrawingEditRt.CommandCenter.WriteInfo("保存成功！");
            //}
        }

        public async void OpenCom()
        {
            var filePaths = await AppRuntime.UISystem.OpenFileDialog();
            if (filePaths == null)
                return;

            string filePath = filePaths[0];

            DocumentUtils.LoadCom(DocumentManager.Current, filePath);
        }

        public void CloseFile()
        {
            AppRuntime.ActiveMainUI.CloseDocument();
            CommandCenter.CommonCommandExecute -= this.Instance_CommandExecute;
            CommandCenter.CommonCommandExecute -= this.Action.Instance_CommandExecute;
        }

        #endregion

    }
}